Load libraries

library(Seurat)
library(princurve)
library(monocle)
library(Matrix)
library(dplyr)
library(RColorBrewer)
library(ggplot2)
library(ggExtra)
library(cowplot)
library(wesanderson)

#Set ggplot theme as classic
theme_set(theme_classic())

Load the full dataset

Hem.data <- readRDS("../QC.filtered.cells.RDS")
Idents(Hem.data) <- Hem.data$Cell_ident
DimPlot(object = Hem.data,
        group.by = "Cell_ident",
        reduction = "spring",
        cols = c("#83c3b8", #"ChP"
                 "#009fda", #"ChP_progenitors"
                 "#68b041", #"Dorso-Medial_pallium"
                 "#e46b6b", #"Hem"
                 "#e3c148", #"Medial_pallium"
                 "#b7d174", #2
                 "grey40", #4
                 "black", #5
                 "#3e69ac" #"Thalamic_eminence"
                 ))

Differentiating neurons trajectory

Neurons.data <-  subset(Hem.data, idents = c("seurat_clusters_2"))

DimPlot(Neurons.data ,
        reduction = "spring",
        pt.size = 1,
        cols =  c("#b7d174")) + NoAxes()

## Split Pallial from Cajal-Retzius cells

p1 <- FeaturePlot(object = Neurons.data ,
            features = c("BP_signature1","LN_signature1"),
            pt.size = 0.5,
            cols = rev(brewer.pal(10,"Spectral")),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- FeaturePlot(object = Neurons.data ,
            features = c("Foxg1", "Trp73"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p1 / p2

Separation between the 2 lineage seems straightforward. We use louvain clustering to split the two.

Neurons.data <- RunPCA(Neurons.data, verbose = FALSE)

Neurons.data <- FindNeighbors(Neurons.data,
                              dims = 1:10,
                              k.param = 8)

Neurons.data <- FindClusters(Neurons.data, resolution = 0.05)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 2835
## Number of edges: 56608
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.9640
## Number of communities: 2
## Elapsed time: 0 seconds
DimPlot(Neurons.data,
        reduction = "spring",
        cols = c("#cc391b","#026c9a"),
        pt.size = 0.5) & NoAxes()

Neurons.data$Lineage <- sapply(as.numeric(Neurons.data$SCT_snn_res.0.05),
                               FUN = function(x) {x= c("Hem","Pallial")[x]})
DimPlot(object = Neurons.data,
        group.by = "Lineage",
        reduction = "spring",
        cols = c("#cc391b","#026c9a"),
        pt.size = 0.5) & NoAxes()

## Fit principale curve on the two lineages

Cajal-Retzius cells

Trajectories.Hem <- Neurons.data@meta.data %>%
                    select("Barcodes", "nUMI", "Spring_1", "Spring_2", "Lineage") %>%
                    filter(Lineage == "Hem")
fit <- principal_curve(as.matrix(Trajectories.Hem[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 45804778678
## Iteration 1---distance^2: 27732113
## Iteration 2---distance^2: 27728318
#The principal curve smoothed
Hem.pc.line <- as.data.frame(fit$s[order(fit$lambda),]) 

#Pseudotime score
Trajectories.Hem$PseudotimeScore <- fit$lambda/max(fit$lambda)
if (cor(Trajectories.Hem$PseudotimeScore, Neurons.data@assays$SCT@data['Hmga2', Trajectories.Hem$Barcodes]) > 0) {
  Trajectories.Hem$PseudotimeScore <- -(Trajectories.Hem$PseudotimeScore - max(Trajectories.Hem$PseudotimeScore))
}

Pallial neurons

Trajectories.Pallial <- Neurons.data@meta.data %>%
                        select("Barcodes", "nUMI", "Spring_1", "Spring_2", "Lineage") %>%
                        filter(Lineage == "Pallial")
fit <- principal_curve(as.matrix(Trajectories.Pallial[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 26984853690
## Iteration 1---distance^2: 22153700
## Iteration 2---distance^2: 22179462
## Iteration 3---distance^2: 22180297
#The principal curve smoothed
Pallial.pc.line <- as.data.frame(fit$s[order(fit$lambda),])

#Pseudotime score
Trajectories.Pallial$PseudotimeScore <- fit$lambda/max(fit$lambda)
if (cor(Trajectories.Pallial$PseudotimeScore, Neurons.data@assays$SCT@data['Hmga2', Trajectories.Pallial$Barcodes]) > 0) {
  Trajectories.Pallial$PseudotimeScore <- -(Trajectories.Pallial$PseudotimeScore - max(Trajectories.Pallial$PseudotimeScore))
}

Combine the two trajectories’ data

Trajectories.neurons <- rbind(Trajectories.Pallial, Trajectories.Hem)
cols <- brewer.pal(n =11, name = "Spectral")

ggplot(Trajectories.neurons, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=PseudotimeScore), size=2, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='Speudotime score') +
  geom_line(data=Pallial.pc.line, color="#026c9a", size=0.77) +
  geom_line(data=Hem.pc.line, color="#cc391b", size=0.77)

## Plot pan-neuronal genes along this axis

Neurons.data <- NormalizeData(Neurons.data, normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")
# Neurog2
p1 <- FeaturePlot(object = Neurons.data,
            features = c("Neurog2"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

Trajectories.neurons$Neurog2 <- Neurons.data@assays$RNA@data["Neurog2", Trajectories.neurons$Barcodes]

p2 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore, y= Neurog2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Tbr1 
p3 <- FeaturePlot(object = Neurons.data ,
            features = c("Tbr1"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()
Trajectories.neurons$Tbr1 <- Neurons.data@assays$RNA@data["Tbr1", Trajectories.neurons$Barcodes]

p4 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore, y= Tbr1)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Mapt 
p5 <- FeaturePlot(object = Neurons.data ,
            features = c("Mapt"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

Trajectories.neurons$Mapt <- Neurons.data@assays$RNA@data["Mapt", Trajectories.neurons$Barcodes]

p6 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore, y= Mapt)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

p1 + p2 + p3 + p4 + p5 + p6 + patchwork::plot_layout(ncol = 2)

Shift Pseudotime in both lineage

Since we observe the first 25% of both trajectories are occupied by few, likely progenitor cells, we shift this cell along the axis

Pseudotime.intervals <- Trajectories.neurons%>%
                          select(Lineage, PseudotimeScore) %>%
                          mutate(Pseudotime.bins = cut(Trajectories.neurons$PseudotimeScore, seq(0, max(Trajectories.neurons$PseudotimeScore) + 0.05, 0.05), dig.lab = 2, right = FALSE)) %>%
                          group_by(Lineage, Pseudotime.bins) %>%
                          summarise(n=n())

ggplot(Pseudotime.intervals, aes(x=Pseudotime.bins, y=n, fill=Lineage)) +
        geom_bar(stat = "identity", width = 0.90) +
        theme(axis.text.x = element_text(angle = 45, hjust=1))+
        scale_fill_manual(values= c("#cc391b", "#026c9a"))

score <- sapply(Trajectories.neurons$PseudotimeScore,
                FUN = function(x) if (x <= 0.2) {x= 0.2} else { x=x })

Trajectories.neurons$PseudotimeScore.shifted <- (score - min(score)) / (max(score) - min(score))
# Neurog2
p1 <- FeaturePlot(object = Neurons.data ,
            features = c("Neurog2"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= Neurog2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Tbr1 
p3 <- FeaturePlot(object = Neurons.data ,
            features = c("Tbr1"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p4 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= Tbr1)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

# Mapt 
p5 <- FeaturePlot(object = Neurons.data ,
            features = c("Mapt"),
            pt.size = 0.5,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes()

p6 <- ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= Mapt)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

p1 + p2 + p3 + p4 + p5 + p6 + patchwork::plot_layout(ncol = 2)

ggplot(Trajectories.neurons, aes(x= PseudotimeScore.shifted, y= nUMI/10000)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA)

rm(list = ls()[!ls() %in% c("Trajectories.neurons")])

Load progenitors with cell cycle trajectory fitted

Progenitors.data <- readRDS("../ProgenitorsDiversity/Progenitors.RDS")
table(Progenitors.data$Cell_ident)
## 
## Dorso-Medial_pallium                  Hem       Medial_pallium 
##                 3451                 1954                 2719

To balance the number of progenitors in both domain we will only work with Hem and Medial_pallium annotated cells. Since we are using pallial cell to contrast CR specific trajectory we think this approximation will not significantly affect our analysis.

Progenitors.data <-  subset(Progenitors.data, idents = c("Hem", "Medial_pallium"))
p1 <- DimPlot(Progenitors.data,
        reduction = "spring",
        pt.size = 0.5,
        cols =  c("#e3c148", "#e46b6b")) + NoAxes()

p2 <- FeaturePlot(object = Progenitors.data,
            features = "Angle.cc",
            pt.size = 0.5,
            cols = rev(colorRampPalette(brewer.pal(n =10, name = "Spectral"))(100)),
            reduction = "spring",
            order = T) & NoAxes()

p3 <- DimPlot(object = Progenitors.data,
        group.by = "Revelio.phase",
        pt.size = 0.5,
        reduction = "spring",
        cols =  c(wes_palette("FantasticFox1")[1:3],"grey40",wes_palette("FantasticFox1")[5])) & NoAxes()

p1 + p2 + p3  + patchwork::plot_layout(ncol = 2)

Combined progenitors and neurons along Pseudotime

# Start with neurons data
Trajectories.all <- Trajectories.neurons %>% select(Barcodes, nUMI, Spring_1, Spring_2, Lineage)

Trajectories.all$Pseudotime <- Trajectories.neurons$PseudotimeScore.shifted + 1
Trajectories.all$Phase <- NA
# Add progenitors data
Trajectories.progenitors <- Progenitors.data@meta.data %>%
                              select(Barcodes, nUMI, Spring_1, Spring_2) %>% 
                              mutate(Lineage= ifelse(Progenitors.data$Cell_ident == "Medial_pallium", "Pallial", "Hem") ,
                                     Pseudotime= Progenitors.data$Angle.cc,
                                     Phase = Progenitors.data$Revelio.phase)
Trajectories.all <- rbind(Trajectories.all, Trajectories.progenitors)

Trajectories.all$Phase <- factor(Trajectories.all$Phase, levels = c("G1.S", "S", "G2", "G2.M", "M.G1"))
p1 <- ggplot(Trajectories.all, aes(Spring_1, Spring_2)) +
        geom_point(aes(color=Pseudotime), size=0.5) + 
        scale_color_gradientn(colours=rev(brewer.pal(n =11, name = "Spectral")), name='Speudotime score')

p2 <- ggplot(Trajectories.all, aes(Spring_1, Spring_2)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a"))

p1 + p2

p1 <- ggplot(Trajectories.all, aes(x= Pseudotime, y= nUMI/10000)) +
        geom_point(aes(color= Phase), size=0.5) +
        scale_color_manual(values= c(wes_palette("FantasticFox1")[1:3],"grey40",wes_palette("FantasticFox1")[5])) +
        geom_smooth(method="loess", n= 50, fill="grey") +
        ylim(0,NA)

p2 <- ggplot(Trajectories.all, aes(x= Pseudotime, y= nUMI/10000)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, fill="grey") +
        ylim(0,NA)

p1 + p2

rm(list = ls()[!ls() %in% c("Trajectories.all")])

Subset the full dataset Seurat object

Hem.data <- readRDS("../QC.filtered.cells.RDS")
Neuro.trajectories <- CreateSeuratObject(counts = Hem.data@assays$RNA@data[, Trajectories.all$Barcodes],
                                         meta.data = Trajectories.all)

spring <- as.matrix(Neuro.trajectories@meta.data %>% select("Spring_1", "Spring_2"))
  
Neuro.trajectories[["spring"]] <- CreateDimReducObject(embeddings = spring, key = "Spring_", assay = DefaultAssay(Neuro.trajectories))
p1 <- FeaturePlot(object = Neuro.trajectories,
            features = "Pseudotime",
            pt.size = 1,
            cols = rev(colorRampPalette(brewer.pal(n =11, name = "Spectral"))(100)),
            reduction = "spring",
            order = T) & NoAxes()

p2 <- DimPlot(object = Neuro.trajectories,
        group.by = "Lineage",
        pt.size = 1,
        reduction = "spring",
        cols =  c("#cc391b", "#026c9a")) & NoAxes()


p3 <- DimPlot(object = Neuro.trajectories,
        group.by = "Phase",
        pt.size = 1,
        reduction = "spring",
        cols =  c(wes_palette("FantasticFox1")[1:3],"grey40",wes_palette("FantasticFox1")[5])) & NoAxes()

p1 + p2 + p3

rm(list = ls()[!ls() %in% c("Neuro.trajectories")])

Normalization

Neuro.trajectories<- NormalizeData(Neuro.trajectories, normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")
Neuro.trajectories <- FindVariableFeatures(Neuro.trajectories, selection.method = "vst", nfeatures = 2000, assay = "RNA")

Plot some genes along pseudotime

trend <- function(Seurat.data,
                  group.by,
                  gene){
  
  data <- Seurat.data@meta.data %>% select(Lineage, Pseudotime, Phase)
  data$Gene <- Seurat.data@assays$RNA@data[gene,]
  
  if (!group.by == "Lineage") {
    p <- ggplot(data=data, aes(x= Pseudotime, y= Gene)) +
        geom_point(aes(color= Phase), size=0.5) +
        scale_color_manual(values= c(wes_palette("FantasticFox1")[1:3],"grey40",wes_palette("FantasticFox1")[5])) +
        geom_smooth(method="loess", n= 50, fill="grey") +
        ylim(0,NA) +
        ggtitle(gene)
  } else {
    p <- ggplot(data=data, aes(x= Pseudotime, y= Gene)) +
        geom_point(aes(color= Lineage), size=0.5) +
        scale_color_manual(values= c("#cc391b", "#026c9a")) +
        geom_smooth(method="loess", n= 50, aes(color= Lineage)) +
        ylim(0,NA) +
        ggtitle(gene)
  }
  
  
  return(p)
}


Plot.Genes.trend <- function(Seurat.data,
                             group.by,
                             genes){
  pList <- mapply(FUN = trend, gene = genes,
                  MoreArgs = list(Seurat.data = Seurat.data, group.by=group.by),
                  SIMPLIFY = FALSE)
  print(x = cowplot::plot_grid(plotlist = pList, ncol = 2))
} 
Plot.Genes.trend(Seurat.data= Neuro.trajectories,
                 group.by = "Lineage",
                 genes= c("Gas1","Sox2",
                          "Neurog2", "Btg2",
                          "Tbr1", "Mapt",
                          "Trp73", "Foxg1"))

Plot.Genes.trend(Seurat.data= Neuro.trajectories,
                 group.by = "Lineage",
                 genes= c("Gmnc", "Mcidas",
                          "Foxj1", "Trp73",
                          "Lhx1", "Cdkn1a"))

Plot.Genes.trend(Seurat.data= Neuro.trajectories,
                 group.by = "Lineage",
                 genes= c("Mki67", "Top2a",
                          "H2afx", "Cdkn1c"))

Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "06 décembre, 2021, 17,57"
#Packages used
sessionInfo()
## R version 4.1.2 (2021-11-01)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.3 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
## 
## locale:
##  [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8    
##  [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
##  [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] splines   stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] wesanderson_0.3.6   cowplot_1.1.1       ggExtra_0.9        
##  [4] RColorBrewer_1.1-2  dplyr_1.0.7         monocle_2.22.0     
##  [7] DDRTree_0.1.5       irlba_2.3.3         VGAM_1.1-5         
## [10] ggplot2_3.3.5       Biobase_2.54.0      BiocGenerics_0.40.0
## [13] Matrix_1.3-4        princurve_2.1.6     SeuratObject_4.0.4 
## [16] Seurat_4.0.5       
## 
## loaded via a namespace (and not attached):
##   [1] Rtsne_0.15            colorspace_2.0-2      deldir_1.0-6         
##   [4] ellipsis_0.3.2        ggridges_0.5.3        spatstat.data_2.1-0  
##   [7] farver_2.1.0          leiden_0.3.9          listenv_0.8.0        
##  [10] ggrepel_0.9.1         fansi_0.5.0           codetools_0.2-18     
##  [13] docopt_0.7.1          knitr_1.36            polyclip_1.10-0      
##  [16] jsonlite_1.7.2        ica_1.0-2             cluster_2.1.2        
##  [19] png_0.1-7             pheatmap_1.0.12       uwot_0.1.10          
##  [22] shiny_1.7.1           sctransform_0.3.2     spatstat.sparse_2.0-0
##  [25] compiler_4.1.2        httr_1.4.2            assertthat_0.2.1     
##  [28] fastmap_1.1.0         lazyeval_0.2.2        limma_3.50.0         
##  [31] later_1.3.0           htmltools_0.5.2       tools_4.1.2          
##  [34] igraph_1.2.9          gtable_0.3.0          glue_1.5.1           
##  [37] RANN_2.6.1            reshape2_1.4.4        Rcpp_1.0.7           
##  [40] slam_0.1-49           scattermore_0.7       jquerylib_0.1.4      
##  [43] vctrs_0.3.8           nlme_3.1-153          lmtest_0.9-39        
##  [46] xfun_0.28             stringr_1.4.0         globals_0.14.0       
##  [49] mime_0.12             miniUI_0.1.1.1        lifecycle_1.0.1      
##  [52] goftest_1.2-3         future_1.23.0         MASS_7.3-54          
##  [55] zoo_1.8-9             scales_1.1.1          spatstat.core_2.3-1  
##  [58] promises_1.2.0.1      spatstat.utils_2.2-0  parallel_4.1.2       
##  [61] yaml_2.2.1            reticulate_1.22       pbapply_1.5-0        
##  [64] gridExtra_2.3         sass_0.4.0            rpart_4.1-15         
##  [67] fastICA_1.2-3         stringi_1.7.6         highr_0.9            
##  [70] densityClust_0.3      rlang_0.4.12          pkgconfig_2.0.3      
##  [73] matrixStats_0.61.0    qlcMatrix_0.9.7       evaluate_0.14        
##  [76] lattice_0.20-45       ROCR_1.0-11           purrr_0.3.4          
##  [79] tensor_1.5            labeling_0.4.2        patchwork_1.1.1      
##  [82] htmlwidgets_1.5.4     tidyselect_1.1.1      parallelly_1.29.0    
##  [85] RcppAnnoy_0.0.19      plyr_1.8.6            magrittr_2.0.1       
##  [88] R6_2.5.1              generics_0.1.1        combinat_0.0-8       
##  [91] DBI_1.1.1             pillar_1.6.4          withr_2.4.3          
##  [94] mgcv_1.8-38           fitdistrplus_1.1-6    survival_3.2-13      
##  [97] abind_1.4-5           tibble_3.1.6          future.apply_1.8.1   
## [100] crayon_1.4.2          KernSmooth_2.23-20    utf8_1.2.2           
## [103] spatstat.geom_2.3-0   plotly_4.10.0         rmarkdown_2.11       
## [106] viridis_0.6.2         grid_4.1.2            data.table_1.14.2    
## [109] FNN_1.1.3             sparsesvd_0.2         HSMMSingleCell_1.14.0
## [112] digest_0.6.29         xtable_1.8-4          tidyr_1.1.4          
## [115] httpuv_1.6.3          munsell_0.5.0         viridisLite_0.4.0    
## [118] bslib_0.3.1

  1. Institute of Psychiatry and Neuroscience of Paris, INSERM U1266, 75014, Paris, France, ↩︎

LS0tCnRpdGxlOiAiQ2FqYWwtUmV0eml1cyBjZWxscyBUcmFqZWN0b3J5IgphdXRob3I6CiAgIC0gTWF0dGhpZXUgTW9yZWF1XltJbnN0aXR1dGUgb2YgUHN5Y2hpYXRyeSBhbmQgTmV1cm9zY2llbmNlIG9mIFBhcmlzLCBJTlNFUk0gVTEyNjYsIDc1MDE0LCBQYXJpcywgRnJhbmNlLCBtYXR0aGlldS5tb3JlYXVAaW5zZXJtLmZyXSBbIVtdKGh0dHBzOi8vb3JjaWQub3JnL3NpdGVzL2RlZmF1bHQvZmlsZXMvaW1hZ2VzL29yY2lkXzE2eDE2LnBuZyldKGh0dHBzOi8vb3JjaWQub3JnLzAwMDAtMDAwMi0yNTkyLTIzNzMpCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgZGZfcHJpbnQ6IHRpYmJsZQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICB0aGVtZTogY29zbW8KICAgIGNzczogIi4uL3N0eWxlLmNzcyIKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ24gPSAnY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGUubGF6eSA9IEZBTFNFKQoKIyBUbyB1c2UgYmlvbWFydCAKbmV3X2NvbmZpZyA8LSBodHRyOjpjb25maWcoc3NsX3ZlcmlmeXBlZXIgPSBGQUxTRSkKaHR0cjo6c2V0X2NvbmZpZyhuZXdfY29uZmlnLCBvdmVycmlkZSA9IEZBTFNFKQpgYGAKCiMgTG9hZCBsaWJyYXJpZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KHByaW5jdXJ2ZSkKbGlicmFyeShtb25vY2xlKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ0V4dHJhKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkod2VzYW5kZXJzb24pCgojU2V0IGdncGxvdCB0aGVtZSBhcyBjbGFzc2ljCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKCkpCmBgYAoKIyBMb2FkIHRoZSBmdWxsIGRhdGFzZXQKCmBgYHtyfQpIZW0uZGF0YSA8LSByZWFkUkRTKCIuLi9RQy5maWx0ZXJlZC5jZWxscy5SRFMiKQpJZGVudHMoSGVtLmRhdGEpIDwtIEhlbS5kYXRhJENlbGxfaWRlbnQKYGBgCgpgYGB7cn0KRGltUGxvdChvYmplY3QgPSBIZW0uZGF0YSwKICAgICAgICBncm91cC5ieSA9ICJDZWxsX2lkZW50IiwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gYygiIzgzYzNiOCIsICMiQ2hQIgogICAgICAgICAgICAgICAgICIjMDA5ZmRhIiwgIyJDaFBfcHJvZ2VuaXRvcnMiCiAgICAgICAgICAgICAgICAgIiM2OGIwNDEiLCAjIkRvcnNvLU1lZGlhbF9wYWxsaXVtIgogICAgICAgICAgICAgICAgICIjZTQ2YjZiIiwgIyJIZW0iCiAgICAgICAgICAgICAgICAgIiNlM2MxNDgiLCAjIk1lZGlhbF9wYWxsaXVtIgogICAgICAgICAgICAgICAgICIjYjdkMTc0IiwgIzIKICAgICAgICAgICAgICAgICAiZ3JleTQwIiwgIzQKICAgICAgICAgICAgICAgICAiYmxhY2siLCAjNQogICAgICAgICAgICAgICAgICIjM2U2OWFjIiAjIlRoYWxhbWljX2VtaW5lbmNlIgogICAgICAgICAgICAgICAgICkpCmBgYAoKIyBEaWZmZXJlbnRpYXRpbmcgbmV1cm9ucyB0cmFqZWN0b3J5CgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtICBzdWJzZXQoSGVtLmRhdGEsIGlkZW50cyA9IGMoInNldXJhdF9jbHVzdGVyc18yIikpCgpEaW1QbG90KE5ldXJvbnMuZGF0YSAsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgcHQuc2l6ZSA9IDEsCiAgICAgICAgY29scyA9ICBjKCIjYjdkMTc0IikpICsgTm9BeGVzKCkKYGBgCiMjIFNwbGl0IFBhbGxpYWwgZnJvbSBDYWphbC1SZXR6aXVzIGNlbGxzCgpgYGB7cn0KcDEgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJCUF9zaWduYXR1cmUxIiwiTE5fc2lnbmF0dXJlMSIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gcmV2KGJyZXdlci5wYWwoMTAsIlNwZWN0cmFsIikpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpCgpwMiA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEgLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIkZveGcxIiwgIlRycDczIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQoKcDEgLyBwMgpgYGAKU2VwYXJhdGlvbiBiZXR3ZWVuIHRoZSAyIGxpbmVhZ2Ugc2VlbXMgc3RyYWlnaHRmb3J3YXJkLiBXZSB1c2UgbG91dmFpbiBjbHVzdGVyaW5nIHRvIHNwbGl0IHRoZSB0d28uCgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtIFJ1blBDQShOZXVyb25zLmRhdGEsIHZlcmJvc2UgPSBGQUxTRSkKCk5ldXJvbnMuZGF0YSA8LSBGaW5kTmVpZ2hib3JzKE5ldXJvbnMuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6MTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsucGFyYW0gPSA4KQoKTmV1cm9ucy5kYXRhIDwtIEZpbmRDbHVzdGVycyhOZXVyb25zLmRhdGEsIHJlc29sdXRpb24gPSAwLjA1KQpgYGAKYGBge3J9CkRpbVBsb3QoTmV1cm9ucy5kYXRhLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSBjKCIjY2MzOTFiIiwiIzAyNmM5YSIpLAogICAgICAgIHB0LnNpemUgPSAwLjUpICYgTm9BeGVzKCkKYGBgCmBgYHtyfQpOZXVyb25zLmRhdGEkTGluZWFnZSA8LSBzYXBwbHkoYXMubnVtZXJpYyhOZXVyb25zLmRhdGEkU0NUX3Nubl9yZXMuMC4wNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSB7eD0gYygiSGVtIiwiUGFsbGlhbCIpW3hdfSkKYGBgCgpgYGB7cn0KRGltUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEsCiAgICAgICAgZ3JvdXAuYnkgPSAiTGluZWFnZSIsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgY29scyA9IGMoIiNjYzM5MWIiLCIjMDI2YzlhIiksCiAgICAgICAgcHQuc2l6ZSA9IDAuNSkgJiBOb0F4ZXMoKQpgYGAKIyMgRml0IHByaW5jaXBhbGUgY3VydmUgb24gdGhlIHR3byBsaW5lYWdlcwoKIyMjIENhamFsLVJldHppdXMgY2VsbHMKCmBgYHtyfQpUcmFqZWN0b3JpZXMuSGVtIDwtIE5ldXJvbnMuZGF0YUBtZXRhLmRhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0KCJCYXJjb2RlcyIsICJuVU1JIiwgIlNwcmluZ18xIiwgIlNwcmluZ18yIiwgIkxpbmVhZ2UiKSAlPiUKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoTGluZWFnZSA9PSAiSGVtIikKYGBgCgpgYGB7cn0KZml0IDwtIHByaW5jaXBhbF9jdXJ2ZShhcy5tYXRyaXgoVHJhamVjdG9yaWVzLkhlbVssYygiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKV0pLAogICAgICAgICAgICAgICAgICAgICAgIHNtb290aGVyPSdsb3dlc3MnLAogICAgICAgICAgICAgICAgICAgICAgIHRyYWNlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgZiA9IC43LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmV0Y2g9MCkKCiNUaGUgcHJpbmNpcGFsIGN1cnZlIHNtb290aGVkCkhlbS5wYy5saW5lIDwtIGFzLmRhdGEuZnJhbWUoZml0JHNbb3JkZXIoZml0JGxhbWJkYSksXSkgCgojUHNldWRvdGltZSBzY29yZQpUcmFqZWN0b3JpZXMuSGVtJFBzZXVkb3RpbWVTY29yZSA8LSBmaXQkbGFtYmRhL21heChmaXQkbGFtYmRhKQoKYGBgCmBgYHtyfQppZiAoY29yKFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlLCBOZXVyb25zLmRhdGFAYXNzYXlzJFNDVEBkYXRhWydIbWdhMicsIFRyYWplY3Rvcmllcy5IZW0kQmFyY29kZXNdKSA+IDApIHsKICBUcmFqZWN0b3JpZXMuSGVtJFBzZXVkb3RpbWVTY29yZSA8LSAtKFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlIC0gbWF4KFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZVNjb3JlKSkKfQpgYGAKCiMjIyBQYWxsaWFsIG5ldXJvbnMKCmBgYHtyfQpUcmFqZWN0b3JpZXMuUGFsbGlhbCA8LSBOZXVyb25zLmRhdGFAbWV0YS5kYXRhICU+JQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoIkJhcmNvZGVzIiwgIm5VTUkiLCAiU3ByaW5nXzEiLCAiU3ByaW5nXzIiLCAiTGluZWFnZSIpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoTGluZWFnZSA9PSAiUGFsbGlhbCIpCiAgICAgICAgICAgICAgICAgIApgYGAKCmBgYHtyfQpmaXQgPC0gcHJpbmNpcGFsX2N1cnZlKGFzLm1hdHJpeChUcmFqZWN0b3JpZXMuUGFsbGlhbFssYygiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKV0pLAogICAgICAgICAgICAgICAgICAgICAgIHNtb290aGVyPSdsb3dlc3MnLAogICAgICAgICAgICAgICAgICAgICAgIHRyYWNlPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgZiA9IC43LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmV0Y2g9MCkKCiNUaGUgcHJpbmNpcGFsIGN1cnZlIHNtb290aGVkClBhbGxpYWwucGMubGluZSA8LSBhcy5kYXRhLmZyYW1lKGZpdCRzW29yZGVyKGZpdCRsYW1iZGEpLF0pCgojUHNldWRvdGltZSBzY29yZQpUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUgPC0gZml0JGxhbWJkYS9tYXgoZml0JGxhbWJkYSkKYGBgCgpgYGB7cn0KaWYgKGNvcihUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUsIE5ldXJvbnMuZGF0YUBhc3NheXMkU0NUQGRhdGFbJ0htZ2EyJywgVHJhamVjdG9yaWVzLlBhbGxpYWwkQmFyY29kZXNdKSA+IDApIHsKICBUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUgPC0gLShUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lU2NvcmUgLSBtYXgoVHJhamVjdG9yaWVzLlBhbGxpYWwkUHNldWRvdGltZVNjb3JlKSkKfQpgYGAKCiMjIENvbWJpbmUgdGhlIHR3byB0cmFqZWN0b3JpZXMnIGRhdGEKCmBgYHtyfQpUcmFqZWN0b3JpZXMubmV1cm9ucyA8LSByYmluZChUcmFqZWN0b3JpZXMuUGFsbGlhbCwgVHJhamVjdG9yaWVzLkhlbSkKYGBgCgpgYGB7cn0KY29scyA8LSBicmV3ZXIucGFsKG4gPTExLCBuYW1lID0gIlNwZWN0cmFsIikKCmdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucywgYWVzKFNwcmluZ18xLCBTcHJpbmdfMikpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1Qc2V1ZG90aW1lU2NvcmUpLCBzaXplPTIsIHNoYXBlPTE2KSArIAogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzPXJldihjb2xzKSwgbmFtZT0nU3BldWRvdGltZSBzY29yZScpICsKICBnZW9tX2xpbmUoZGF0YT1QYWxsaWFsLnBjLmxpbmUsIGNvbG9yPSIjMDI2YzlhIiwgc2l6ZT0wLjc3KSArCiAgZ2VvbV9saW5lKGRhdGE9SGVtLnBjLmxpbmUsIGNvbG9yPSIjY2MzOTFiIiwgc2l6ZT0wLjc3KQpgYGAKIyMgUGxvdCBwYW4tbmV1cm9uYWwgZ2VuZXMgYWxvbmcgdGhpcyBheGlzCgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtIE5vcm1hbGl6ZURhdGEoTmV1cm9ucy5kYXRhLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCwgYXNzYXkgPSAiUk5BIikKYGBgCgpgYGB7ciBmaWcuZGltPWMoOSwxMCl9CiMgTmV1cm9nMgpwMSA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiTmV1cm9nMiIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKClRyYWplY3Rvcmllcy5uZXVyb25zJE5ldXJvZzIgPC0gTmV1cm9ucy5kYXRhQGFzc2F5cyRSTkFAZGF0YVsiTmV1cm9nMiIsIFRyYWplY3Rvcmllcy5uZXVyb25zJEJhcmNvZGVzXQoKcDIgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLCB5PSBOZXVyb2cyKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCiMgVGJyMSAKcDMgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJUYnIxIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQpUcmFqZWN0b3JpZXMubmV1cm9ucyRUYnIxIDwtIE5ldXJvbnMuZGF0YUBhc3NheXMkUk5BQGRhdGFbIlRicjEiLCBUcmFqZWN0b3JpZXMubmV1cm9ucyRCYXJjb2Rlc10KCnA0IDwtIGdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucywgYWVzKHg9IFBzZXVkb3RpbWVTY29yZSwgeT0gVGJyMSkpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpCgojIE1hcHQgCnA1IDwtIEZlYXR1cmVQbG90KG9iamVjdCA9IE5ldXJvbnMuZGF0YSAsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiTWFwdCIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKClRyYWplY3Rvcmllcy5uZXVyb25zJE1hcHQgPC0gTmV1cm9ucy5kYXRhQGFzc2F5cyRSTkFAZGF0YVsiTWFwdCIsIFRyYWplY3Rvcmllcy5uZXVyb25zJEJhcmNvZGVzXQoKcDYgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLCB5PSBNYXB0KSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCnAxICsgcDIgKyBwMyArIHA0ICsgcDUgKyBwNiArIHBhdGNod29yazo6cGxvdF9sYXlvdXQobmNvbCA9IDIpCmBgYAoKIyMgU2hpZnQgUHNldWRvdGltZSBpbiBib3RoIGxpbmVhZ2UKClNpbmNlIHdlIG9ic2VydmUgdGhlIGZpcnN0IDI1JSBvZiBib3RoIHRyYWplY3RvcmllcyBhcmUgb2NjdXBpZWQgYnkgZmV3LCBsaWtlbHkgcHJvZ2VuaXRvciBjZWxscywgd2Ugc2hpZnQgdGhpcyBjZWxsIGFsb25nIHRoZSBheGlzCgpgYGB7cn0KUHNldWRvdGltZS5pbnRlcnZhbHMgPC0gVHJhamVjdG9yaWVzLm5ldXJvbnMlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoTGluZWFnZSwgUHNldWRvdGltZVNjb3JlKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoUHNldWRvdGltZS5iaW5zID0gY3V0KFRyYWplY3Rvcmllcy5uZXVyb25zJFBzZXVkb3RpbWVTY29yZSwgc2VxKDAsIG1heChUcmFqZWN0b3JpZXMubmV1cm9ucyRQc2V1ZG90aW1lU2NvcmUpICsgMC4wNSwgMC4wNSksIGRpZy5sYWIgPSAyLCByaWdodCA9IEZBTFNFKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoTGluZWFnZSwgUHNldWRvdGltZS5iaW5zKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2Uobj1uKCkpCgpnZ3Bsb3QoUHNldWRvdGltZS5pbnRlcnZhbHMsIGFlcyh4PVBzZXVkb3RpbWUuYmlucywgeT1uLCBmaWxsPUxpbmVhZ2UpKSArCiAgICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC45MCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKSsKICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKQpgYGAKYGBge3J9CnNjb3JlIDwtIHNhcHBseShUcmFqZWN0b3JpZXMubmV1cm9ucyRQc2V1ZG90aW1lU2NvcmUsCiAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSBpZiAoeCA8PSAwLjIpIHt4PSAwLjJ9IGVsc2UgeyB4PXggfSkKClRyYWplY3Rvcmllcy5uZXVyb25zJFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkIDwtIChzY29yZSAtIG1pbihzY29yZSkpIC8gKG1heChzY29yZSkgLSBtaW4oc2NvcmUpKQpgYGAKCgpgYGB7ciBmaWcuZGltPWMoOSwxMCl9CiMgTmV1cm9nMgpwMSA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBOZXVyb25zLmRhdGEgLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIk5ldXJvZzIiKSwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpCgpwMiA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyh4PSBQc2V1ZG90aW1lU2NvcmUuc2hpZnRlZCwgeT0gTmV1cm9nMikpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpCgojIFRicjEgCnAzIDwtIEZlYXR1cmVQbG90KG9iamVjdCA9IE5ldXJvbnMuZGF0YSAsCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiVGJyMSIpLAogICAgICAgICAgICBwdC5zaXplID0gMC41LAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkKCnA0IDwtIGdncGxvdChUcmFqZWN0b3JpZXMubmV1cm9ucywgYWVzKHg9IFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkLCB5PSBUYnIxKSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBMaW5lYWdlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKCIjY2MzOTFiIiwgIiMwMjZjOWEiKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgYWVzKGNvbG9yPSBMaW5lYWdlKSkgKwogICAgICAgIHlsaW0oMCxOQSkKCiMgTWFwdCAKcDUgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhICwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJNYXB0IiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKQoKcDYgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5uZXVyb25zLCBhZXMoeD0gUHNldWRvdGltZVNjb3JlLnNoaWZ0ZWQsIHk9IE1hcHQpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBhZXMoY29sb3I9IExpbmVhZ2UpKSArCiAgICAgICAgeWxpbSgwLE5BKQoKcDEgKyBwMiArIHAzICsgcDQgKyBwNSArIHA2ICsgcGF0Y2h3b3JrOjpwbG90X2xheW91dChuY29sID0gMikKYGBgCmBgYHtyfQpnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyh4PSBQc2V1ZG90aW1lU2NvcmUuc2hpZnRlZCwgeT0gblVNSS8xMDAwMCkpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpCmBgYApgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCJUcmFqZWN0b3JpZXMubmV1cm9ucyIpXSkKYGBgCgojIExvYWQgcHJvZ2VuaXRvcnMgd2l0aCBjZWxsIGN5Y2xlIHRyYWplY3RvcnkgZml0dGVkCgpgYGB7cn0KUHJvZ2VuaXRvcnMuZGF0YSA8LSByZWFkUkRTKCIuLi9Qcm9nZW5pdG9yc0RpdmVyc2l0eS9Qcm9nZW5pdG9ycy5SRFMiKQpgYGAKCmBgYHtyfQp0YWJsZShQcm9nZW5pdG9ycy5kYXRhJENlbGxfaWRlbnQpCmBgYAoKVG8gYmFsYW5jZSB0aGUgbnVtYmVyIG9mIHByb2dlbml0b3JzIGluIGJvdGggZG9tYWluIHdlIHdpbGwgb25seSB3b3JrIHdpdGggKkhlbSogYW5kICpNZWRpYWxfcGFsbGl1bSogYW5ub3RhdGVkIGNlbGxzLiBTaW5jZSB3ZSBhcmUgdXNpbmcgcGFsbGlhbCBjZWxsIHRvIGNvbnRyYXN0IENSIHNwZWNpZmljIHRyYWplY3Rvcnkgd2UgdGhpbmsgdGhpcyBhcHByb3hpbWF0aW9uIHdpbGwgbm90IHNpZ25pZmljYW50bHkgYWZmZWN0IG91ciBhbmFseXNpcy4KCmBgYHtyfQpQcm9nZW5pdG9ycy5kYXRhIDwtICBzdWJzZXQoUHJvZ2VuaXRvcnMuZGF0YSwgaWRlbnRzID0gYygiSGVtIiwgIk1lZGlhbF9wYWxsaXVtIikpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDYsIDQpfQpwMSA8LSBEaW1QbG90KFByb2dlbml0b3JzLmRhdGEsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICBjb2xzID0gIGMoIiNlM2MxNDgiLCAiI2U0NmI2YiIpKSArIE5vQXhlcygpCgpwMiA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBQcm9nZW5pdG9ycy5kYXRhLAogICAgICAgICAgICBmZWF0dXJlcyA9ICJBbmdsZS5jYyIsCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSByZXYoY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKG4gPTEwLCBuYW1lID0gIlNwZWN0cmFsIikpKDEwMCkpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpCgpwMyA8LSBEaW1QbG90KG9iamVjdCA9IFByb2dlbml0b3JzLmRhdGEsCiAgICAgICAgZ3JvdXAuYnkgPSAiUmV2ZWxpby5waGFzZSIsCiAgICAgICAgcHQuc2l6ZSA9IDAuNSwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gIGMod2VzX3BhbGV0dGUoIkZhbnRhc3RpY0ZveDEiKVsxOjNdLCJncmV5NDAiLHdlc19wYWxldHRlKCJGYW50YXN0aWNGb3gxIilbNV0pKSAmIE5vQXhlcygpCgpwMSArIHAyICsgcDMgICsgcGF0Y2h3b3JrOjpwbG90X2xheW91dChuY29sID0gMikKYGBgCgojIENvbWJpbmVkIHByb2dlbml0b3JzIGFuZCBuZXVyb25zIGFsb25nIFBzZXVkb3RpbWUKCmBgYHtyfQojIFN0YXJ0IHdpdGggbmV1cm9ucyBkYXRhClRyYWplY3Rvcmllcy5hbGwgPC0gVHJhamVjdG9yaWVzLm5ldXJvbnMgJT4lIHNlbGVjdChCYXJjb2RlcywgblVNSSwgU3ByaW5nXzEsIFNwcmluZ18yLCBMaW5lYWdlKQoKVHJhamVjdG9yaWVzLmFsbCRQc2V1ZG90aW1lIDwtIFRyYWplY3Rvcmllcy5uZXVyb25zJFBzZXVkb3RpbWVTY29yZS5zaGlmdGVkICsgMQpUcmFqZWN0b3JpZXMuYWxsJFBoYXNlIDwtIE5BCgpgYGAKCmBgYHtyfQojIEFkZCBwcm9nZW5pdG9ycyBkYXRhClRyYWplY3Rvcmllcy5wcm9nZW5pdG9ycyA8LSBQcm9nZW5pdG9ycy5kYXRhQG1ldGEuZGF0YSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KEJhcmNvZGVzLCBuVU1JLCBTcHJpbmdfMSwgU3ByaW5nXzIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKExpbmVhZ2U9IGlmZWxzZShQcm9nZW5pdG9ycy5kYXRhJENlbGxfaWRlbnQgPT0gIk1lZGlhbF9wYWxsaXVtIiwgIlBhbGxpYWwiLCAiSGVtIikgLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHNldWRvdGltZT0gUHJvZ2VuaXRvcnMuZGF0YSRBbmdsZS5jYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBoYXNlID0gUHJvZ2VuaXRvcnMuZGF0YSRSZXZlbGlvLnBoYXNlKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKCmBgYAoKYGBge3J9ClRyYWplY3Rvcmllcy5hbGwgPC0gcmJpbmQoVHJhamVjdG9yaWVzLmFsbCwgVHJhamVjdG9yaWVzLnByb2dlbml0b3JzKQoKVHJhamVjdG9yaWVzLmFsbCRQaGFzZSA8LSBmYWN0b3IoVHJhamVjdG9yaWVzLmFsbCRQaGFzZSwgbGV2ZWxzID0gYygiRzEuUyIsICJTIiwgIkcyIiwgIkcyLk0iLCAiTS5HMSIpKQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg5LDMpfQpwMSA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLmFsbCwgYWVzKFNwcmluZ18xLCBTcHJpbmdfMikpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj1Qc2V1ZG90aW1lKSwgc2l6ZT0wLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnM9cmV2KGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKSksIG5hbWU9J1NwZXVkb3RpbWUgc2NvcmUnKQoKcDIgPC0gZ2dwbG90KFRyYWplY3Rvcmllcy5hbGwsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKQoKcDEgKyBwMgpgYGAKCmBgYHtyIGZpZy5kaW09Yyg5LDMpfQpwMSA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLmFsbCwgYWVzKHg9IFBzZXVkb3RpbWUsIHk9IG5VTUkvMTAwMDApKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IFBoYXNlKSwgc2l6ZT0wLjUpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBjKHdlc19wYWxldHRlKCJGYW50YXN0aWNGb3gxIilbMTozXSwiZ3JleTQwIix3ZXNfcGFsZXR0ZSgiRmFudGFzdGljRm94MSIpWzVdKSkgKwogICAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBuPSA1MCwgZmlsbD0iZ3JleSIpICsKICAgICAgICB5bGltKDAsTkEpCgpwMiA8LSBnZ3Bsb3QoVHJhamVjdG9yaWVzLmFsbCwgYWVzKHg9IFBzZXVkb3RpbWUsIHk9IG5VTUkvMTAwMDApKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IExpbmVhZ2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBmaWxsPSJncmV5IikgKwogICAgICAgIHlsaW0oMCxOQSkKCnAxICsgcDIKYGBgCmBgYHtyfQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIGMoIlRyYWplY3Rvcmllcy5hbGwiKV0pCmBgYAoKIyBTdWJzZXQgdGhlIGZ1bGwgZGF0YXNldCBTZXVyYXQgb2JqZWN0CgpgYGB7cn0KSGVtLmRhdGEgPC0gcmVhZFJEUygiLi4vUUMuZmlsdGVyZWQuY2VsbHMuUkRTIikKYGBgCgpgYGB7cn0KTmV1cm8udHJhamVjdG9yaWVzIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBIZW0uZGF0YUBhc3NheXMkUk5BQGRhdGFbLCBUcmFqZWN0b3JpZXMuYWxsJEJhcmNvZGVzXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhLmRhdGEgPSBUcmFqZWN0b3JpZXMuYWxsKQoKc3ByaW5nIDwtIGFzLm1hdHJpeChOZXVyby50cmFqZWN0b3JpZXNAbWV0YS5kYXRhICU+JSBzZWxlY3QoIlNwcmluZ18xIiwgIlNwcmluZ18yIikpCiAgCk5ldXJvLnRyYWplY3Rvcmllc1tbInNwcmluZyJdXSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gc3ByaW5nLCBrZXkgPSAiU3ByaW5nXyIsIGFzc2F5ID0gRGVmYXVsdEFzc2F5KE5ldXJvLnRyYWplY3RvcmllcykpCmBgYAoKYGBge3IgZmlnLmRpbT1jKDYsIDEyKX0KcDEgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm8udHJhamVjdG9yaWVzLAogICAgICAgICAgICBmZWF0dXJlcyA9ICJQc2V1ZG90aW1lIiwKICAgICAgICAgICAgcHQuc2l6ZSA9IDEsCiAgICAgICAgICAgIGNvbHMgPSByZXYoY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKG4gPTExLCBuYW1lID0gIlNwZWN0cmFsIikpKDEwMCkpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpCgpwMiA8LSBEaW1QbG90KG9iamVjdCA9IE5ldXJvLnRyYWplY3RvcmllcywKICAgICAgICBncm91cC5ieSA9ICJMaW5lYWdlIiwKICAgICAgICBwdC5zaXplID0gMSwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gIGMoIiNjYzM5MWIiLCAiIzAyNmM5YSIpKSAmIE5vQXhlcygpCgoKcDMgPC0gRGltUGxvdChvYmplY3QgPSBOZXVyby50cmFqZWN0b3JpZXMsCiAgICAgICAgZ3JvdXAuYnkgPSAiUGhhc2UiLAogICAgICAgIHB0LnNpemUgPSAxLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSAgYyh3ZXNfcGFsZXR0ZSgiRmFudGFzdGljRm94MSIpWzE6M10sImdyZXk0MCIsd2VzX3BhbGV0dGUoIkZhbnRhc3RpY0ZveDEiKVs1XSkpICYgTm9BeGVzKCkKCnAxICsgcDIgKyBwMwpgYGAKCgpgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSBjKCJOZXVyby50cmFqZWN0b3JpZXMiKV0pCmBgYAoKIyMgTm9ybWFsaXphdGlvbgoKYGBge3J9Ck5ldXJvLnRyYWplY3RvcmllczwtIE5vcm1hbGl6ZURhdGEoTmV1cm8udHJhamVjdG9yaWVzLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCwgYXNzYXkgPSAiUk5BIikKYGBgCgpgYGB7cn0KTmV1cm8udHJhamVjdG9yaWVzIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKE5ldXJvLnRyYWplY3Rvcmllcywgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwLCBhc3NheSA9ICJSTkEiKQpgYGAKIyMgUGxvdCBzb21lIGdlbmVzIGFsb25nIHBzZXVkb3RpbWUKCmBgYHtyfQp0cmVuZCA8LSBmdW5jdGlvbihTZXVyYXQuZGF0YSwKICAgICAgICAgICAgICAgICAgZ3JvdXAuYnksCiAgICAgICAgICAgICAgICAgIGdlbmUpewogIAogIGRhdGEgPC0gU2V1cmF0LmRhdGFAbWV0YS5kYXRhICU+JSBzZWxlY3QoTGluZWFnZSwgUHNldWRvdGltZSwgUGhhc2UpCiAgZGF0YSRHZW5lIDwtIFNldXJhdC5kYXRhQGFzc2F5cyRSTkFAZGF0YVtnZW5lLF0KICAKICBpZiAoIWdyb3VwLmJ5ID09ICJMaW5lYWdlIikgewogICAgcCA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD0gUHNldWRvdGltZSwgeT0gR2VuZSkpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gUGhhc2UpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMod2VzX3BhbGV0dGUoIkZhbnRhc3RpY0ZveDEiKVsxOjNdLCJncmV5NDAiLHdlc19wYWxldHRlKCJGYW50YXN0aWNGb3gxIilbNV0pKSArCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIG49IDUwLCBmaWxsPSJncmV5IikgKwogICAgICAgIHlsaW0oMCxOQSkgKwogICAgICAgIGdndGl0bGUoZ2VuZSkKICB9IGVsc2UgewogICAgcCA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD0gUHNldWRvdGltZSwgeT0gR2VuZSkpICsKICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gTGluZWFnZSksIHNpemU9MC41KSArCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYygiI2NjMzkxYiIsICIjMDI2YzlhIikpICsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgbj0gNTAsIGFlcyhjb2xvcj0gTGluZWFnZSkpICsKICAgICAgICB5bGltKDAsTkEpICsKICAgICAgICBnZ3RpdGxlKGdlbmUpCiAgfQogIAogIAogIHJldHVybihwKQp9CgoKUGxvdC5HZW5lcy50cmVuZCA8LSBmdW5jdGlvbihTZXVyYXQuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lcyl7CiAgcExpc3QgPC0gbWFwcGx5KEZVTiA9IHRyZW5kLCBnZW5lID0gZ2VuZXMsCiAgICAgICAgICAgICAgICAgIE1vcmVBcmdzID0gbGlzdChTZXVyYXQuZGF0YSA9IFNldXJhdC5kYXRhLCBncm91cC5ieT1ncm91cC5ieSksCiAgICAgICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpCiAgcHJpbnQoeCA9IGNvd3Bsb3Q6OnBsb3RfZ3JpZChwbG90bGlzdCA9IHBMaXN0LCBuY29sID0gMikpCn0gCmBgYAoKCmBgYHtyIGZpZy5kaW09Yyg5LDgpfQpQbG90LkdlbmVzLnRyZW5kKFNldXJhdC5kYXRhPSBOZXVyby50cmFqZWN0b3JpZXMsCiAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiTGluZWFnZSIsCiAgICAgICAgICAgICAgICAgZ2VuZXM9IGMoIkdhczEiLCJTb3gyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTmV1cm9nMiIsICJCdGcyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiVGJyMSIsICJNYXB0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJwNzMiLCAiRm94ZzEiKSkKYGBgCgpgYGB7ciBmaWcuZGltPWMoOSw2KX0KUGxvdC5HZW5lcy50cmVuZChTZXVyYXQuZGF0YT0gTmV1cm8udHJhamVjdG9yaWVzLAogICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gIkxpbmVhZ2UiLAogICAgICAgICAgICAgICAgIGdlbmVzPSBjKCJHbW5jIiwgIk1jaWRhcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkZveGoxIiwgIlRycDczIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiTGh4MSIsICJDZGtuMWEiKSkKYGBgCgpgYGB7ciBmaWcuZGltPWMoOSw1KX0KUGxvdC5HZW5lcy50cmVuZChTZXVyYXQuZGF0YT0gTmV1cm8udHJhamVjdG9yaWVzLAogICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gIkxpbmVhZ2UiLAogICAgICAgICAgICAgICAgIGdlbmVzPSBjKCJNa2k2NyIsICJUb3AyYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkgyYWZ4IiwgIkNka24xYyIpKQpgYGAKCgojIFNlc3Npb24gSW5mbwoKYGBge3J9CiNkYXRlCmZvcm1hdChTeXMudGltZSgpLCAiJWQgJUIsICVZLCAlSCwlTSIpCgojUGFja2FnZXMgdXNlZApzZXNzaW9uSW5mbygpCmBgYA==